"
A ChangeRecord represents a change recorded on a file in fileOut format.

It includes a type (more needs to be done here), and additional information for certain types such as method defs which need class and protocol name.
"
Class {
	#name : 'ChangeRecord',
	#superclass : 'Object',
	#instVars : [
		'file',
		'position',
		'type',
		'class',
		'protocol',
		'meta',
		'stamp'
	],
	#category : 'System-Changes-Records',
	#package : 'System-Changes',
	#tag : 'Records'
}

{ #category : 'testing' }
ChangeRecord >> <= anotherOne [

	self stamp ifNil: [ ^ false ].
	anotherOne stamp ifNil: [ ^ true ].
	^ self timeStamp <= anotherOne timeStamp
]

{ #category : 'testing' }
ChangeRecord >> classIncludesSelector [

	| aClass |
	^ (aClass := self methodClass) isNotNil
			and: [aClass includesSelector: self methodSelector]
]

{ #category : 'accessing' }
ChangeRecord >> commentClass [
	| commentClass |
	type == #classComment ifFalse: [^ nil].
	(Smalltalk includesKey: class asSymbol) ifFalse: [^ nil].
	commentClass := Smalltalk at: class asSymbol.
	^meta ifTrue: [commentClass class]
		ifFalse: [commentClass]
]

{ #category : 'initialization' }
ChangeRecord >> file: f position: p type: t [
	file := f.
	position := p.
	type := t
]

{ #category : 'initialization' }
ChangeRecord >> file: f position: p type: t class: c protocol: aProtocol meta: m stamp: s [
	self file: f position: p type: t.
	class := c.
	protocol := aProtocol.
	meta := m.
	stamp := s
]

{ #category : 'initialization' }
ChangeRecord >> fileIn [
	"File the receiver in.  If I represent a method or a class-comment, file the method in and make a note of it in the recent-submissions list; if I represent a do-it, then, well, do it."

	self methodClass ifNotNil: [ :methodClass |
		methodClass
			compile: self string
			classified: protocol
			withStamp: stamp
			notifying: nil ].
	type == #doIt ifTrue: [
		| string |
		string := self string.
		(string beginsWith: '----') ifFalse: [
			self class compiler evaluate: string ] ].
	type == #classComment ifTrue: [
		(Smalltalk globals at: class asSymbol)
			comment: self string
			stamp: stamp ]
]

{ #category : 'accessing' }
ChangeRecord >> fileName [
	^file ifNotNil: [ file name ] ifNil: [ '<no file>' ]
]

{ #category : 'accessing' }
ChangeRecord >> fileOutOn: aFileStream [
	"File the receiver out on the given file stream"

	| aString chunkWriteStream |
	chunkWriteStream := ChunkWriteStream on: aFileStream.

	type == #method ifTrue: [
			chunkWriteStream bang.
			aString := class asString , (meta
				            ifTrue: [ ' class methodsFor: ' ]
				            ifFalse: [ ' methodsFor: ' ]) , protocol asString printString.
			stamp ifNotNil: [ aString := aString , ' stamp: ''' , stamp , '''' ].

			chunkWriteStream
				nextPut: aString;
				cr ].

	type == #preamble ifTrue: [ chunkWriteStream bang ].

	type == #classComment ifTrue: [
			chunkWriteStream
				bang;
				nextPut: class asString , ' commentStamp: ' , stamp storeString;
				cr ].

	chunkWriteStream nextPut: self string.
	type == #method ifTrue: [ chunkWriteStream nextPut: ' ' ].
	chunkWriteStream cr
]

{ #category : 'testing' }
ChangeRecord >> isMetaClassChange [
	^meta
]

{ #category : 'testing' }
ChangeRecord >> isMethodDefinedInImage [
	"answer whether the method represented by the receiver is present in the image"

	^ self type = #method
		and: [self classIncludesSelector]
]

{ #category : 'testing' }
ChangeRecord >> isMethodNotDefinedInImage [
	"answer whether the method represented by the receiver is not present in the image.
	pay attention is it not just isMethodDefinedInImage not"

	| aClass |
	^ self type = #method and:
			[(aClass := self methodClass) isNil or:
				[(aClass includesSelector: self methodSelector) not]]
]

{ #category : 'accessing' }
ChangeRecord >> methodClass [
	| methodClass |
	type == #method
		ifFalse: [ ^ nil ].
	(Smalltalk globals includesKey: class asSymbol)
		ifFalse: [ ^ nil ].
	methodClass := Smalltalk globals at: class asSymbol.
	^ meta
		ifTrue: [ methodClass class ]
		ifFalse: [ methodClass ]
]

{ #category : 'accessing' }
ChangeRecord >> methodClassName [
	^ meta
		ifTrue: [ class , ' class' ]
		ifFalse: [ class ]
]

{ #category : 'accessing' }
ChangeRecord >> methodSelector [
	^ type == #method
		ifTrue: [ (Smalltalk globals at: class ifAbsent: [ Object ]) compiler parseSelector: self string ]
]

{ #category : 'accessing' }
ChangeRecord >> position [
	^ position
]

{ #category : 'printing' }
ChangeRecord >> printOn: aStream [

	self type printOn: aStream.
	self stamp ifNotNil: [ :s | s printOn: aStream ]
]

{ #category : 'accessing' }
ChangeRecord >> protocol [

	^ protocol
]

{ #category : 'accessing' }
ChangeRecord >> sourceCode [

	self type= #preamble ifTrue: [ ^ #preamble printString ].
	self type= #doIt ifTrue: [ ^ #preamble printString ].
	self type= #classComment ifTrue: [ self commentClass ifNotNil: [ :comment | ^ comment comment ]].

	^ self string
]

{ #category : 'accessing' }
ChangeRecord >> stamp [
	^ stamp
]

{ #category : 'accessing' }
ChangeRecord >> stamp: threePartString [

	stamp := threePartString
]

{ #category : 'accessing' }
ChangeRecord >> string [
	| copy |
	copy := file readOnlyCopy.
	copy position: position.
	[ ^ (ChunkReadStream on: copy) next ]
		ensure: [ copy close ]
]

{ #category : 'accessing' }
ChangeRecord >> timeStamp [
	"Answer a TimeStamp that corresponds to my (text) stamp"

	| tokens |
	tokens := self stamp findTokens: Character separators.
	^ tokens size > 2
		ifTrue: [
			[
			| time date |
			date := Date readFrom: (tokens at: tokens size - 1) pattern: 'dd-mm-yyyy'.
			time := Time fromString: tokens last.
			DateAndTime date: date time: time ]
				on: Error
				do: [ :ex | ex return: DateAndTime new ] ]
		ifFalse: [ DateAndTime new ]
]

{ #category : 'accessing' }
ChangeRecord >> type [
	^ type
]
